%% Matrix Algebra vs Element-wise Algebra 

%Generate 2x2 matrix
a=rand(2,2)

%By default, MATLAB performs a matrix operation
a*a

%If you want an element-wise multiplication you need the '.*'. 
a.*a

%This is same for division:  
a/a 

%which is the same as:
a/inv(a)
%where 'inv(a)' is the matrix inverse

%This divides element-wise
a./a

%create vector
b=rand(2,1)

%This gives and error because there is no matrix method to multiply two
% 2x1 vectors. 
b*b

%'c' is matrix transpose of 'b'
c=b.'
%'c' is now 1x2

%this is a dot product (inner product)
c*b




%% Anonymous functions 

%From MATLAB documentation:
% What Are Anonymous Functions?
% An anonymous function is a function that is not stored in a program file, 
% but is associated with a variable whose data type is function_handle. 
% Anonymous functions can accept inputs and return outputs, just as standard 
% functions do. However, they can contain only a single executable statement.

%This creates an anonymous function with it's function handle assigned to
%'f'
f=@(x) exp(-x)

%We can call 'f' just like any other function
f(2)

%See 'doc anonymous functions' for more examples


%% Numerical integration using the mid-point method

%We want to calculate the integral of some function of 'x' from 'x=a' to
%'x=b'

%Create a simple anonymous function
f=@(x) exp(-x)


a=.1;           %start point of integration
b=2;            %end point of integration

h_req=.001;     %Use steps size of 'h_req' or smaller. 

%Let's do some math to get equal sized steps between 'a' and 'b'
Nsteps=ceil((b-a)/h_req)+1;     %The  '+1' for the end point
EndPoints=linspace(a,b,Nsteps); %Notice the new command 'linspace'

%Calculate and check spacing
h=EndPoints(2)-EndPoints(1)

%Peform the integration
Int_Result=0; %set accumulation variable to zero

for ii=1:length(EndPoints)-1    %note 'length' function. 
    x_mid=EndPoints(ii)+h/2;    %find mid-point of this section
    Int_Result=Int_Result+f(x_mid)*h;   %calculate rectangle area and add
end

%Display some results and compare to known answer
Int_Result
Int_Analytical=-exp(-b)+exp(-a)
Int_Diff=Int_Analytical-Int_Result;

%we can get the function definition as a string like this (see 'help functions'):
fout=functions(f)
s=fout.function;

fprintf('Integral of: %s is Numerical: %3.4g  Analytical: %g\n',s(5:end),Int_Result,Int_Analytical)
fprintf('Difference is: %g\n',Int_Diff)

%% Using NIntegrate class

%Make a class and use this to perform numerical integration
% See NIntegrate.m

%Create function handle for exp(-x)
f=@(x) exp(-x)

%Create object of the NIntegrate class
NI=NIntegrate()

%Setup properties
NI.h_req=.1
NI.a=1
NI.b=3
NI.find_h()
NI.f=f

%Perform integration by calling the 'IntFucntion' method
NI.IntFunction()

%The result
NI.Int_Result

%Compare
Int_Analytical=-exp(-NI.b)+exp(-NI.a)
Int_Diff=Int_Analytical-NI.Int_Result;

fout=functions(f)
s=fout.function;
fprintf('Integral of: %s is Numerical: %3.4g  Analytical: %g\n',s(5:end),NI.Int_Result,Int_Analytical)
fprintf('Difference is: %g\n',Int_Diff)























